package com.liuyjy.base.common.util;

import cn.hutool.core.util.IdcardUtil;
import com.liuyjy.base.common.entity.UserCardNoParseInfo;
import lombok.extern.slf4j.Slf4j;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;

import static java.util.regex.Pattern.compile;

/**
 * @Author liuyjy
 * @Date 2022/10/13 15:28
 * @Description: 身份证识别
 **/
@Slf4j
public class CardNoUtil {

    public static void main(String[] args) {
        //String idCard="83000019770226004X";
        String idCard = "341204201301131010";
        System.out.println("身份证是否正确:" + isCorrect(idCard));
        System.out.println("身份证是否正确:" + IdcardUtil.isValidCard(idCard));
        System.out.println("身份证是否正确:" + noVerifyCardNo(idCard));
        System.out.println("身份证获取出生日期、性别、年龄:" + getBirAgeSex(idCard));
        System.out.println("身份证获取出生日期:" + getBirthday(idCard));
        System.out.println("身份证获取性别::" + getSex(idCard));
        System.out.println("身份证获取年龄::" + getAge(idCard));
    }

    /**
     * 证件号检查
     *
     * @param idNo 账号
     */
    private static boolean noVerifyCardNo(String idNo) {

        if (EmptyUtil.isEmpty(idNo)) {
            return false;
        }
        if (idNo.contains("PDS") || idNo.contains("PDM") || idNo.contains("PDT") ||
                idNo.contains("pds") || idNo.contains("pdm") || idNo.contains("pdt")) {
            return false;
        }
        try {
            if (IdcardUtil.isValidCard(idNo)) {
                return true;
            }
            if (IdcardUtil.isValidTWCard(idNo)) {
                return true;
            }
            if (IdcardUtil.isValidHKCard(idNo)) {
                return true;
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
        return false;
    }

    /**
     * 身份证是否存在
     *
     * @param idCard 身份证
     * @return boolean
     */
    public static boolean isCorrect(String idCard) {
        Matcher matcher = compile("^(\\d{6})(19|20)(\\d{2})(1[0-2]|0[1-9])(0[1-9]|[1-2][0-9]|3[0-1])(\\d{3})(\\d|X|x)?$").matcher(idCard);
        int[] prefix = new int[]{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
        int[] suffix = new int[]{1, 0, 10, 9, 8, 7, 6, 5, 4, 3, 2};
        if (matcher.matches()) {
            Map<String, String> cityMap = initCityMap();
            if (cityMap.get(idCard.substring(0, 2)) == null) {
                return false;
            }
            //用来保存前17位各自乖以加权因子后的总和
            int idCardWiSum = 0;
            for (int i = 0; i < 17; i++) {
                idCardWiSum += Integer.parseInt(idCard.substring(i, i + 1)) * prefix[i];
            }

            //计算出校验码所在数组的位置
            int idCardMod = idCardWiSum % 11;
            //得到最后一位身份证号码
            String idCardLast = idCard.substring(17);

            //如果等于2，则说明校验码是10，身份证号码最后一位应该是X
            if (idCardMod == 2) {
                return "x".equalsIgnoreCase(idCardLast);
            } else {
                //用计算出的验证码与最后一位身份证号码匹配，如果一致，说明通过，否则是无效的身份证号码
                return idCardLast.equals(suffix[idCardMod] + "");
            }
        }
        return false;
    }

    /**
     * 通过身份证号码获取出生日期、性别、年龄
     *
     * @param idCard 身份证
     * @return 返回的出生日期格式：1990-01-01 性别格式：2-女，1-男
     */
    public static UserCardNoParseInfo getBirAgeSex(String idCard) {
        if (!isCorrect(idCard)) {
            log.info("身份证号不正确：{}", idCard);
            return null;
        }
        String birthday = "";
        Integer age = null;
        Integer sex = null;

        int year = Calendar.getInstance().get(Calendar.YEAR);
        char[] number = idCard.toCharArray();
        boolean flag = true;
        if (number.length == 15) {
            for (int x = 0; x < number.length; x++) {
                if (!flag) {
                    return null;
                }
                flag = Character.isDigit(number[x]);
            }
        } else if (number.length == 18) {
            for (int x = 0; x < number.length - 1; x++) {
                if (!flag) {
                    return null;
                }
                flag = Character.isDigit(number[x]);
            }
        }
        if (flag && idCard.length() == 15) {
            birthday = "19" + idCard.substring(6, 8) + "-" + idCard.substring(8, 10) + "-"
                    + idCard.substring(10, 12);
            sex = Integer.parseInt(idCard.substring(idCard.length() - 3, idCard.length()))
                    % 2 == 0 ? 2 : 1;
            age = (year - Integer.parseInt("19" + idCard.substring(6, 8)));
        } else if (flag && idCard.length() == 18) {
            birthday = idCard.substring(6, 10) + "-" + idCard.substring(10, 12) + "-"
                    + idCard.substring(12, 14);
            sex = Integer.parseInt(idCard.substring(idCard.length() - 4, idCard.length() - 1))
                    % 2 == 0 ? 2 : 1;
            age = (year - Integer.parseInt(idCard.substring(6, 10)));
        }
        UserCardNoParseInfo info = new UserCardNoParseInfo();
        info.setAge(age);
        info.setBirthday(birthday);
        info.setSex(sex);
        return info;
    }

    /**
     * 根据身份证号判断性别
     *
     * @param idCard 身份证号
     * @return 1男 2 女
     */
    public static String getBirthday(String idCard) {
        String birthday = "";
        if (!isCorrect(idCard)) {
            log.info("身份证号不正确：{}", idCard);
            return birthday;
        }
        if (idCard.length() == 15) {
            birthday = "19" + idCard.substring(6, 8) + "-" + idCard.substring(8, 10) + "-" + idCard.substring(10, 12);
        } else if (idCard.length() == 18) {
            birthday = idCard.substring(6, 10) + "-" + idCard.substring(10, 12) + "-" + idCard.substring(12, 14);
        }
        return birthday;
    }

    /**
     * 根据身份证的号码算出当前身份证持有者的年龄
     *
     * @return Integer
     */
    public static Integer getAge(String idCard) {
        if (!isCorrect(idCard)) {
            log.info("身份证号不正确：{}", idCard);
            return null;
        }
        String year;
        String yue;
        String day;
        if (idCard.length() == 18) {
            year = idCard.substring(6).substring(0, 4);// 得到年份
            yue = idCard.substring(10).substring(0, 2);// 得到月份
            day = idCard.substring(12).substring(0, 2);//得到日
        } else {
            year = "19" + idCard.substring(6, 8);// 年份
            yue = idCard.substring(8, 10);// 月份
            day = idCard.substring(10, 12);//日
        }
        Date date = new Date();// 得到当前的系统时间
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        String fyear = format.format(date).substring(0, 4);// 当前年份
        String fyue = format.format(date).substring(5, 7);// 月份
        String fday = format.format(date).substring(8, 10);//
        int age = 0;
        if (Integer.parseInt(yue) == Integer.parseInt(fyue)) {//如果月份相同
            //说明已经过了生日或者今天是生日
            if (Integer.parseInt(day) <= Integer.parseInt(fday)) {
                age = Integer.parseInt(fyear) - Integer.parseInt(year);
            } else {
                age = Integer.parseInt(fyear) - Integer.parseInt(year) - 1;
            }
        } else {

            if (Integer.parseInt(yue) < Integer.parseInt(fyue)) {
                //如果当前月份大于出生月份
                age = Integer.parseInt(fyear) - Integer.parseInt(year);
            } else {
                //如果当前月份小于出生月份,说明生日还没过
                age = Integer.parseInt(fyear) - Integer.parseInt(year) - 1;
            }
        }
        //System.out.println("age = " + age);
        return age;
    }

    /**
     * 根据身份证号判断性别
     *
     * @param idCard 身份证号
     * @return 1男 2 女
     */
    public static Integer getSex(String idCard) {
        if (!isCorrect(idCard)) {
            log.info("身份证号不正确：{}", idCard);
            return null;
        }
        int gender = 0;
        if (idCard.length() == 18) {
            //如果身份证号18位，取身份证号倒数第二位
            char c = idCard.charAt(idCard.length() - 2);
            gender = Integer.parseInt(String.valueOf(c));
        } else {
            //如果身份证号15位，取身份证号最后一位
            char c = idCard.charAt(idCard.length() - 1);
            gender = Integer.parseInt(String.valueOf(c));
        }
        //System.out.println("gender = " + gender);
        if (gender % 2 == 1) {
            return 1;
        } else {
            return 2;
        }
    }

    private static Map<String, String> initCityMap() {
        Map<String, String> cityMap = new HashMap<String, String>();
        cityMap.put("11", "北京");
        cityMap.put("12", "天津");
        cityMap.put("13", "河北");
        cityMap.put("14", "山西");
        cityMap.put("15", "内蒙古");

        cityMap.put("21", "辽宁");
        cityMap.put("22", "吉林");
        cityMap.put("23", "黑龙江");

        cityMap.put("31", "上海");
        cityMap.put("32", "江苏");
        cityMap.put("33", "浙江");
        cityMap.put("34", "安徽");
        cityMap.put("35", "福建");
        cityMap.put("36", "江西");
        cityMap.put("37", "山东");

        cityMap.put("41", "河南");
        cityMap.put("42", "湖北");
        cityMap.put("43", "湖南");
        cityMap.put("44", "广东");
        cityMap.put("45", "广西");
        cityMap.put("46", "海南");

        cityMap.put("50", "重庆");
        cityMap.put("51", "四川");
        cityMap.put("52", "贵州");
        cityMap.put("53", "云南");
        cityMap.put("54", "西藏");

        cityMap.put("61", "陕西");
        cityMap.put("62", "甘肃");
        cityMap.put("63", "青海");
        cityMap.put("64", "宁夏");
        cityMap.put("65", "新疆");

        cityMap.put("71", "台湾");
        cityMap.put("81", "香港");
        cityMap.put("82", "澳门");
        cityMap.put("83", "台湾");
        cityMap.put("91", "国外");
        return cityMap;
    }
}
